﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Win32;

namespace SuperQuery
{
    /// <summary>
    /// WPF implementation of the SuperQuery view factory
    /// </summary>
    public class WPFViewFactory : Views.IViewFactory
    {
        #region Implemetation of IViewFactory

        /// <summary>
        /// Show the Edit Database view
        /// </summary>
        /// <param name="dataBaseToEdit">The database we are editing</param>
        /// <param name="parentView">A parent view that will "own" this view</param>
        public void EditDatabase(Models.Database dataBaseToEdit, Views.IView parentView)
        {
            EditDatabase editDb = new EditDatabase(dataBaseToEdit);
            SetOwner(editDb, parentView);
            editDb.ShowDialog();
        }

        /// <summary>
        /// Show the Add Database view
        /// </summary>
        /// <param name="parentQueryTab">The QueryTab view we are adding the databases to</param>
        /// <param name="parentView">A parent view that will "own" this view</param>
        public void AddDatabase(Views.IQueryView parentQueryTab, Views.IView parentView)
        {
            AddDatabases addDb = new AddDatabases(parentQueryTab);
            SetOwner(addDb, parentView);
            addDb.ShowDialog();
        }

        /// <summary>
        /// Show the Remove Databases view
        /// </summary>
        /// <param name="parentQueryTab">The QueryTab view we are removing the databases from</param>
        /// <param name="parentView">A parent view that will "own" this view</param>
        public void RemoveDatabases(Views.IQueryView parentQueryTab, Views.IView parentView)
        {
            RemoveDatabases removeDb = new RemoveDatabases(parentQueryTab);
            SetOwner(removeDb, parentView);
            removeDb.ShowDialog();
        }

        /// <summary>
        /// Show the Database LList Upgrade view
        /// </summary>
        /// <param name="dbListToUpgrade">The list of databases we will be upgrading</param>
        /// <param name="parentView">A parent view that will "own" this view</param>
        public void DBListUpgrade(List<Models.Database> dbListToUpgrade, Views.IView parentView)
        {
            DBListUpgrade upgrade = new DBListUpgrade(dbListToUpgrade);
            SetOwner(upgrade, parentView);
            upgrade.ShowDialog();
        }

        /// <summary>
        /// Export the canCloseApplication sets associated with a list of databases
        /// </summary>
        /// <param name="dbListToExport">The list of databases that contain canCloseApplication sets to export</param>
        /// <param name="parentView">A parent view that will "own" this view</param>
        public void ExportResults(List<Models.Database> dbListToExport, Views.IView parentView)
        {
            ExportResults export = new ExportResults(dbListToExport);
            SetOwner(export, parentView);
            export.ShowDialog();
        }

        /// <summary>
        /// Show a dialog with a list of querys to save and ask the user to select the ones that they want to save
        /// </summary>
        /// <param name="queryViewsToSave">The list of possible queries to save</param>
        /// <param name="parentView">The parent view</param>
        /// <returns>A List of the querys the user has selected to save or NULL is cancel was pressed</returns>
        public List<Views.IQueryView> SaveItems(List<Views.IQueryView> queryViewsToSave, Views.IView parentView)
        {
            List<Views.IQueryView> result = null;

            if (queryViewsToSave.Count(query => query.IsDirty) == 0)
            {
                // If there are no queries that need saving then return an empty list
                result = new List<Views.IQueryView>();
            }
            else
            {
                // Some of th equeries need saving so show the "Save Items" dialog
                SaveItems saveItems = new SaveItems(queryViewsToSave);
                SetOwner(saveItems, parentView);
                saveItems.ShowDialog();
                result = saveItems.QueriesSelectedToSave;
            }

            return result;
        }

        /// <summary>
        /// Show the About view
        /// </summary>
        /// <param name="parentView">A parent view that will "own" this view</param>
        public void About(Views.IView parentView)
        {
            About about = new About();
            SetOwner(about, parentView);
            about.ShowDialog();
        }

        /// <summary>
        /// Ask the user a question and return the canCloseApplication
        /// </summary>
        /// <param name="message">The message to display</param>
        /// <param name="title">The title of the message</param>
        /// <param name="showCancel">If true then a "Cancel" button is shown</param>
        /// <returns>True if the user clicks "Yes", false if th euser clicks "No" or null if the user clicks "Cancel"</returns>
        public bool? AskQuestion(string message, string title, bool showCancel)
        {
            // Display message box
            MessageBoxButton buttons = showCancel ? MessageBoxButton.YesNoCancel : MessageBoxButton.YesNo;
            MessageBoxResult msgResult = MessageBox.Show(message, title, buttons, MessageBoxImage.Question);

            bool? result;

            // Get the canCloseApplication and return true, false or null depending on which button was clicked
            if (msgResult == MessageBoxResult.Yes)
            {
                result = true;
            }
            else if (msgResult == MessageBoxResult.No)
            {
                result = false;
            }
            else
            {
                result = null;
            }

            return result;
        }

        /// <summary>
        /// Display an error message to the user
        /// </summary>
        /// <param name="message">The error mesage text</param>
        /// <param name="title">The title of the error message</param>
        public void DisplayError(string message, string title)
        {
            MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Exclamation);
        }

        /// <summary>
        /// Display an information message to the user
        /// </summary>
        /// <param name="message">The mesage text</param>
        /// <param name="title">The title of the error message</param>
        public void DisplayMessage(string message, string title)
        {
            MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Information);
        }

        /// <summary>
        /// Show an open file dialog and return the name of the file selected, or string.empty if Cancel was clicked
        /// </summary>
        /// <param name="title">The title for the open file dialog</param>
        /// <param name="defaultExt">The default extension</param>
        /// <param name="filters">The filters to add to the list of file types</param>
        /// <param name="parentView">A parent view that will "own" this view</param>
        /// <returns>The file name or string.empty if cancel was pressed</returns>
        public string GetFileToOpen(string title, string defaultExt, string filters, Views.IView parentView)
        {
            string selectedFile = string.Empty;

            OpenFileDialog openFileDlg = new OpenFileDialog
            {
                Title = title,
                ValidateNames = true,
                Multiselect = false,
                DefaultExt = defaultExt,
                Filter = filters
            };

            // Convert parentView into a window if possible
            Window parent = (parentView is Window) ? (Window)parentView : null;

            // Get a file name to open.
            // NB: CommonDialog functions return nullable boolean but the return value will ALWAYS have a value.
            //     A value of null indicates that the dialog has remained open becuase validation, etc has failed. As we are
            //     not handling the "Open" button click then this possibility will never occur to us
            bool? dialogResult = openFileDlg.ShowDialog(parent);
            if (dialogResult.Value)
            {
                selectedFile = openFileDlg.FileName;
            }

            return selectedFile;
        }

        /// <summary>
        /// Show a save as dialog box and return a file name to save data with, or string.Empty if cancel was clicked
        /// </summary>
        /// <param name="title">The dialog title</param>
        /// <param name="defaultExt">The default extension to use</param>
        /// <param name="filters">The filters to add the list of file types</param>
        /// <param name="defaultFileName">The default file name to suggest as a file name to save under</param>
        /// <param name="parentView">A parent view that will "own" this view</param>
        /// <returns>The file name or string.empty if cancel was pressed</returns>
        public string GetFileToSave(string title, string defaultExt, string filters, string defaultFileName, Views.IView parentView)
        {
            string selectedFile = string.Empty;

            SaveFileDialog saveFileDialog = new SaveFileDialog
            {
                Title = title,
                ValidateNames = true,
                DefaultExt = defaultExt,
                Filter = filters,
                FileName = defaultFileName
            };

            // Convert parentView into a window if possible
            Window parent = (parentView is Window) ? (Window)parentView : null;

            // Get a file name to save.
            // NB: CommonDialog functions return nullable boolean but the return value will ALWAYS have a value.
            //     A value of null indicates that the dialog has remained open becuase validation, etc has failed. As we are
            //     not handling the "Save" button click then this possibility will never occur to us
            bool? dialogResult = saveFileDialog.ShowDialog(parent);
            if (dialogResult.Value)
            {
                selectedFile = saveFileDialog.FileName;
            }

            return selectedFile;
        }
        #endregion

        /// <summary>
        /// If parentView is a window then set it as the child windows parent
        /// </summary>
        /// <param name="childWindow">The window whose parent we will set</param>
        /// <param name="parentView">The parent view that which (if a window) will be set as the childWindow's parent</param>
        private void SetOwner(Window childWindow, Views.IView parentView)
        {
            if ((parentView != null) && (parentView is Window))
            {
                childWindow.Owner = (Window)parentView;
            }
        }
    }
}
